package com.yearner.reviewplan;

import apijson.Log;
import apijson.orm.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.yearner.reviewplan.apijson.*;
import org.springframework.beans.BeansException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import unitauto.MethodUtil;
import unitauto.NotNull;

import javax.naming.Context;
import java.lang.reflect.Modifier;
import java.util.List;

/**
 * @author pengyg
 * @since 2019/10/11
 */
@EnableScheduling
@EnableAsync(proxyTargetClass = true)
@SpringBootApplication
public class Application implements ApplicationContextAware {

    public static void main(String[] args) throws Exception {

        SpringApplication.run(Application.class, args);
        Log.DEBUG = false;  // 上线生产环境前改为 false，可不输出 APIJSONORM 的日志 以及 SQLException 的原始(敏感)信息
        MyAPIJSONApplication.init();
    }
    private static final String TAG = "Application";

    static {
        // APIJSON 配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        // 使用本项目的自定义处理类
        MyAPIJSONApplication.DEFAULT_APIJSON_CREATOR = new MyAPIJSONCreator() {

            public Parser<String> createParser() {
                return new DemoParser();
            }
            @Override
            public FunctionParser createFunctionParser() {
                return new DemoFunctionParser();
            }

            @Override
            public Verifier<String> createVerifier() {
                return new DemoVerifier();
            }

            @Override
            public SQLConfig createSQLConfig() {
                return new DemoSQLConfig();
            }
            @Override
            public SQLExecutor createSQLExecutor() {
                return new DemoSQLExecutor();
            }

        };

        // APIJSON 配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


        // UnitAuto 单元测试配置  https://github.com/TommyLemon/UnitAuto  <<<<<<<<<<<<<<<<<<<<<<<<<<<

//		UnitAutoApp.init();

        // 适配 Spring 注入的类及 Context 等环境相关的类
        final MethodUtil.InstanceGetter ig = MethodUtil.INSTANCE_GETTER;
        MethodUtil.INSTANCE_GETTER = new MethodUtil.InstanceGetter() {

            @Override
            public Object getInstance(@NotNull Class<?> clazz, List<MethodUtil.Argument> classArgs, Boolean reuse) throws Exception {
                if (APPLICATION_CONTEXT != null && ApplicationContext.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(APPLICATION_CONTEXT.getClass())) {
                    return APPLICATION_CONTEXT;
                }

                if (reuse != null && reuse && (classArgs == null || classArgs.isEmpty())) {
                    return APPLICATION_CONTEXT.getBean(clazz);
                }

                return ig.getInstance(clazz, classArgs, reuse);
            }
        };

        // 排除转换 JSON 异常的类，一般是 Context 等环境相关的类
        final MethodUtil.JSONCallback jc = MethodUtil.JSON_CALLBACK;
        MethodUtil.JSON_CALLBACK = new MethodUtil.JSONCallback() {

            @Override
            public JSONObject newSuccessResult() {
                return jc.newSuccessResult();
            }

            @Override
            public JSONObject newErrorResult(Throwable e) {
                return jc.newErrorResult(e);
            }

            @Override
            public JSONObject parseJSON(String type, Object value) {
                if (value == null || unitauto.JSON.isBooleanOrNumberOrString(value) || value instanceof JSON || value instanceof Enum) {
                    return jc.parseJSON(type, value);
                }

                if (value instanceof ApplicationContext
                        || value instanceof Context
                        || value instanceof javax.validation.MessageInterpolator.Context
                        || value instanceof org.omg.CORBA.Context
                        || value instanceof org.apache.catalina.Context
                        || value instanceof ch.qos.logback.core.Context
                ) {
                    value = value.toString();
                }
                else {
                    try {
                        value = JSON.parse(JSON.toJSONString(value, new PropertyFilter() {
                            @Override
                            public boolean apply(Object object, String name, Object value) {
                                if (value == null) {
                                    return true;
                                }

                                if (value instanceof ApplicationContext
                                        || value instanceof Context
                                        || value instanceof javax.validation.MessageInterpolator.Context
                                        || value instanceof org.omg.CORBA.Context
                                        || value instanceof org.apache.catalina.Context
                                        || value instanceof ch.qos.logback.core.Context
                                ) {
                                    return false;
                                }

                                return Modifier.isPublic(value.getClass().getModifiers());
                            }
                        }));
                    } catch (Exception e) {
                        Log.e(TAG, "toJSONString  catch \n" + e.getMessage());
                    }
                }

                return jc.parseJSON(type, value);
            }

        };

        // UnitAuto 单元测试配置  https://github.com/TommyLemon/UnitAuto  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    }

    private static ApplicationContext APPLICATION_CONTEXT;
    public static ApplicationContext getApplicationContext() {
        return APPLICATION_CONTEXT;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        APPLICATION_CONTEXT = applicationContext;
    }
}
